package com.ygsoft.activiti.service.impl;

import com.ygsoft.activiti.model.CompleteTask;
import com.ygsoft.activiti.model.MyCompleteTask;
import com.ygsoft.activiti.model.MyTask;
import com.ygsoft.activiti.reposirory.CompleteTaskReposirory;
import com.ygsoft.activiti.service.TasksServiceInf;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 任务流程
 *
 * @author zhx
 * @create 2017-11-14 9:32
 **/
@Component
public class TasksServiceImpl implements TasksServiceInf {
    private Logger logger = LoggerFactory.getLogger(TasksServiceImpl.class);

    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private CompleteTaskReposirory completeTaskReposirory;

    /**
     * TODO 分页处理
     * @param userId
     * @param roleList
     * @return
     */
    @Override
    public List<MyTask> getTasksByUserId(String userId, List<String> roleList, int page, int pageSize) {
        if(page>0){
            page = page -1;
        }

        //获取当前用户Id 或者在某个用户组下的
        List<Task> tasks =taskService.createTaskQuery().taskCandidateGroupIn(roleList).listPage(page,pageSize);

        List<MyTask> tempList = new ArrayList<>();

        for(Task t: tasks){
            MyTask myTask = new MyTask(t);

            String processInstanceId = t.getProcessInstanceId();
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();

            ExecutionEntity execution =(ExecutionEntity) runtimeService.createExecutionQuery().executionId(t.getExecutionId()).singleResult();


            String business_key = execution.getBusinessKey();
            String processDefinitionKey = pi.getProcessDefinitionKey();
            String startMan = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .singleResult().getStartUserId();
            myTask.setStartMan(startMan);
            myTask.setBussinessId(business_key);
            myTask.setBussinessKey(processDefinitionKey);

            tempList.add(myTask);
        }

        return tempList;
    }

    @Override
    public Page<CompleteTask> getMyCompleteTask(String userId, int page, int pageSize) {
        Sort sort = new Sort(Sort.Direction.DESC, "time");

        page = page -1;

        Pageable pageable = new PageRequest(page, pageSize, sort);


        Page<CompleteTask> byUserId = completeTaskReposirory.findByUserId(userId, pageable);

        return byUserId;
    }

    @Override
    public List<MyCompleteTask> getMyCompleteTask(List<CompleteTask> listCompleteTask) {
        List<MyCompleteTask> myCompleteTasks = new ArrayList<>();

        for(CompleteTask completeTask:listCompleteTask){
            HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(completeTask.getTaskId()).singleResult();
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processDefinitionId(completeTask.getProcessInstanceId()).singleResult();
            MyCompleteTask myCompleteTask = new MyCompleteTask(completeTask,historicTaskInstance,historicProcessInstance);

            myCompleteTasks.add(myCompleteTask);
        }

        return  myCompleteTasks;
    }


    @Override
    public boolean completeTask(String taskId,String userId, String userName, String comment) {
        Task task=taskService.createTaskQuery().taskId(taskId).singleResult();
        //利用任务对象，获取流程实例id
        String processInstancesId=task.getProcessInstanceId();

        System.out.println(processInstancesId);

        // 添加批注时候的审核人，通常应该从session获取
        Authentication.setAuthenticatedUserId(userId);

        taskService.addComment(taskId,processInstancesId,comment);

        taskService.complete(taskId);

        return  true;
    }

    @Override
    public String getNextTask(String procInstanceId) {
        // 1、首先是根据流程ID获取当前任务：
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(procInstanceId).list();
        String nextName = "";
        for (Task task : tasks) {
            // 2、然后根据当前任务获取当前流程的流程定义，然后根据流程定义获得所有的节点：
            ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                    .getDeployedProcessDefinition(task.getProcessDefinitionId());
            List<ActivityImpl> activitiList = def.getActivities(); // rs是指RepositoryService的实例
            // 3、根据任务获取当前流程执行ID，执行实例以及当前流程节点的ID：
            String excId = task.getExecutionId();

            ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(excId)
                    .singleResult();
            String activitiId = execution.getActivityId();
            // 4、然后循环activitiList
            // 并判断出当前流程所处节点，然后得到当前节点实例，根据节点实例获取所有从当前节点出发的路径，然后根据路径获得下一个节点实例：
            for (ActivityImpl activityImpl : activitiList) {
                String id = activityImpl.getId();
                if (activitiId.equals(id)) {
                    logger.debug("当前任务：" + activityImpl.getProperty("name")); // 输出某个节点的某种属性
                    List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();// 获取从某个节点出来的所有线路
                    for (PvmTransition tr : outTransitions) {
                        PvmActivity ac = tr.getDestination(); // 获取线路的终点节点
                        logger.debug("下一步任务任务：" + ac.getProperty("name"));
                        nextName =(String) ac.getProperty("name");
                    }
                    break;
                }
            }
        }
        return nextName;
    }

    @Override
    public String getNowTaskName(String procInstanceId) {
        HistoricActivityInstance historicActivityInstance = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(procInstanceId)
                .unfinished()//未完成的活动(任务)
                .singleResult();

        if(historicActivityInstance!=null){
            return historicActivityInstance.getActivityName();
        }else{
            return "";
        }
    }

    @Override
    public String getNowTaskId(String procInstanceId) {
        HistoricActivityInstance historicActivityInstance = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(procInstanceId)
                .unfinished()//未完成的活动(任务)
                .singleResult();

        if(historicActivityInstance!=null){
            return historicActivityInstance.getTaskId();
        }else{
            return "";
        }
    }

    @Override
    public Task getTaskByTaskId(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();


        return task;
    }

    @Override
    public List<String> getRoleListByTaskId(String taskId) {
        List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(taskId);

        List<String> returnTemp = new ArrayList<>();

        for(IdentityLink i:identityLinksForTask){
            if(StringUtils.isNotEmpty(i.getGroupId())){
                returnTemp.add(i.getGroupId());
            }
        }

        return returnTemp;
    }

    @Override
    public List<String> getUserListByTaskId(String taskId) {
        List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(taskId);

        List<String> returnTemp = new ArrayList<>();
        for(IdentityLink i:identityLinksForTask){
            if(StringUtils.isNotEmpty(i.getUserId())){
                returnTemp.add(i.getUserId());
            }
        }

        return returnTemp;
    }

    @Override
    public boolean jumpTask(String processId, String targetTaskDefinitionKey) {
        /**
         *取当前到了哪一步业务节点  HistoricActivityInstance 为数据模型
         */
        HistoricActivityInstance historicActivityInstance = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId)
                .unfinished()//未完成的活动(任务)
                .singleResult();

        if(historicActivityInstance == null){
            return false;
        }

        TaskEntity currentTask = (TaskEntity) taskService.createTaskQuery().processInstanceId(processId).singleResult();

        (( org.activiti.engine.impl.RuntimeServiceImpl)runtimeService).getCommandExecutor().execute(
                new Command<Object>() {
                    @Override
                    public Object execute(CommandContext commandContext) {
                        ExecutionEntity execution = commandContext.getExecutionEntityManager().findExecutionById(processId);
                        execution.destroyScope("jump");  //
                        ProcessDefinitionImpl processDefinition = execution.getProcessDefinition();
                        ActivityImpl findActivity = processDefinition.findActivity(targetTaskDefinitionKey);
                        //创建新任务
                        execution.setActivity(findActivity);
                        execution.executeActivity(findActivity);

                        //删除当前的任务
                        //不能删除当前正在执行的任务，所以要先清除掉关联
                        currentTask.setExecutionId(null);
                        taskService.saveTask(currentTask);
                        taskService.deleteTask(currentTask.getId(), true);

                        return execution;
                    }
                }
        );

        return true;
    }


    @Override
    public boolean stopProcessId(String processId) {
        runtimeService.suspendProcessInstanceById(processId);

        return true;
    }

    @Override
    public boolean startProcessId(String processId) {
        runtimeService.activateProcessInstanceById(processId);
        return true;
    }

    @Override
    public boolean finishProcessId(String processId) throws Exception {
        HistoricActivityInstance historicActivityInstance = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processId)
                .unfinished()//未完成的活动(任务)
                .singleResult();

        if(historicActivityInstance==null){
            return false;
        }

        Map<String, Object> variables = new HashMap<String, Object>();

        ActivityImpl endActivity = findActivitiImpl( historicActivityInstance.getTaskId(), "end");
        turnTransition( historicActivityInstance.getTaskId(), endActivity.getId(), variables);
        return false;
    }

    /**
     * 流程转向操作
     *
     * @param taskId
     *            当前任务ID
     * @param activityId
     *            目标节点任务ID
     * @param variables
     *            流程变量
     * @throws Exception
     */
    private void turnTransition(String taskId, String activityId,
                                Map<String, Object> variables) throws Exception {
        // 当前节点
        ActivityImpl currActivity = findActivitiImpl(taskId, null);
        // 清空当前流向
        List<PvmTransition> oriPvmTransitionList = clearTransition(currActivity);

        // 创建新流向
        TransitionImpl newTransition = currActivity.createOutgoingTransition();
        // 目标节点
        ActivityImpl pointActivity = findActivitiImpl(taskId, activityId);
        // 设置新流向的目标节点
        newTransition.setDestination(pointActivity);

        // 执行转向任务
        taskService.complete(taskId, variables);
        // 删除目标节点新流入
        pointActivity.getIncomingTransitions().remove(newTransition);

        // 还原以前流向
        restoreTransition(currActivity, oriPvmTransitionList);
    }

    /**
     * 清空指定活动节点流向
     *
     * @param activityImpl
     *            活动节点
     * @return 节点流向集合
     */
    private List<PvmTransition> clearTransition(ActivityImpl activityImpl) {
        // 存储当前节点所有流向临时变量
        List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
        // 获取当前节点所有流向，存储到临时变量，然后清空
        List<PvmTransition> pvmTransitionList = activityImpl
                .getOutgoingTransitions();
        for (PvmTransition pvmTransition : pvmTransitionList) {
            oriPvmTransitionList.add(pvmTransition);
        }
        pvmTransitionList.clear();

        return oriPvmTransitionList;
    }

    /**
     * 还原指定活动节点流向
     *
     * @param activityImpl
     *            活动节点
     * @param oriPvmTransitionList
     *            原有节点流向集合
     */
    private void restoreTransition(ActivityImpl activityImpl,
                                   List<PvmTransition> oriPvmTransitionList) {
        // 清空现有流向
        List<PvmTransition> pvmTransitionList = activityImpl
                .getOutgoingTransitions();
        pvmTransitionList.clear();
        // 还原以前流向
        for (PvmTransition pvmTransition : oriPvmTransitionList) {
            pvmTransitionList.add(pvmTransition);
        }
    }

    /**
     * 根据任务ID和节点ID获取活动节点 <br>
     *
     * @param taskId
     *            任务ID
     * @param activityId
     *            活动节点ID <br>
     *            如果为null或""，则默认查询当前活动节点 <br>
     *            如果为"end"，则查询结束节点 <br>
     *
     * @return
     * @throws Exception
     */
    private ActivityImpl findActivitiImpl(String taskId, String activityId)
            throws Exception {
        // 取得流程定义
        ProcessDefinitionEntity processDefinition = findProcessDefinitionEntityByTaskId(taskId);

        // 获取当前活动节点ID
        if (StringUtils.isBlank(activityId)) {
            activityId = findTaskById(taskId).getTaskDefinitionKey();
        }

        // 根据流程定义，获取该流程实例的结束节点
        if (activityId.toUpperCase().equals("END")) {
            for (ActivityImpl activityImpl : processDefinition.getActivities()) {
                List<PvmTransition> pvmTransitionList = activityImpl
                        .getOutgoingTransitions();
                if (pvmTransitionList.isEmpty()) {
                    return activityImpl;
                }
            }
        }

        // 根据节点ID，获取对应的活动节点
        ActivityImpl activityImpl = ((ProcessDefinitionImpl) processDefinition)
                .findActivity(activityId);

        return activityImpl;
    }

    /**
     * 根据任务ID获取流程定义
     *
     * @param taskId
     *            任务ID
     * @return
     * @throws Exception
     */
    private ProcessDefinitionEntity findProcessDefinitionEntityByTaskId(
            String taskId) throws Exception {
        // 取得流程定义
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(findTaskById(taskId)
                        .getProcessDefinitionId());

        if (processDefinition == null) {
            throw new Exception("流程定义未找到!");
        }

        return processDefinition;
    }

    /**
     * 根据任务ID获得任务实例
     *
     * @param taskId
     *            任务ID
     * @return
     * @throws Exception
     */
    private TaskEntity findTaskById(String taskId) throws Exception {
        TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(
                taskId).singleResult();
        if (task == null) {
            throw new Exception("任务实例未找到!");
        }
        return task;
    }




}
